package gui;

import api.API;
import api.Message;
import dropbox.Config;
import dropbox.Dropbox;
import error.ConfigFileNotFoundException;
import error.FileCorruptedException;
import error.NotLoggedInException;
import error.UserAlreadyExistsException;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

public class DBM extends JFrame {

    private static final long serialVersionUID = 1L;
    
    private JPanel          contentPane;
    private JTextArea       editor;
    private MessageTabs     tabber;
    private List<Message>   control;
    private API             messenger;
    private Timer           updater;
    private Config          config;
    
    // Main
    public static void main(String[] args) {
        DBM frame = new DBM();
        frame.setVisible(true);

    }
    
    // Konstruktor
    public DBM() {

        // Egyszerű bezárás definiálás,méret, és név
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 700, 500);
        this.setTitle("DBM: kilépve");

        // Tároló eszköz megalkotása
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new BorderLayout(0, 0));

        // Felosztó panel megalkotása, knoténerhez adás
        JSplitPane splitPane = new JSplitPane();
        splitPane.setContinuousLayout(true);
        splitPane.setResizeWeight(0.95);
        splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        splitPane.setDividerSize(4);
        splitPane.setBorder(null);
        contentPane.add(splitPane, BorderLayout.CENTER);

        // Újabb panel
        JPanel tabberPanel = new JPanel();
        splitPane.setLeftComponent(tabberPanel);
        tabberPanel.setLayout(new BorderLayout(0, 0));
        
        // Üzenetek helye(középen)
        tabber = new MessageTabs();
        tabberPanel.add(tabber, BorderLayout.CENTER);

        // Szerkesztő rész
        JPanel editorPanel = new JPanel();
        splitPane.setRightComponent(editorPanel);
        editorPanel.setLayout(new BorderLayout(0, 0));

        // Író felület megalkotás
        editor = new JTextArea();
        editor.setAutoscrolls(true);
        editor.addKeyListener(new InputKeyListener());
        editor.setBorder(new LineBorder(UIManager.getColor("CheckBox.focus")));
        editor.setLineWrap(true);

        // Scrollozható
        JScrollPane scroll = new JScrollPane(editor);
        editorPanel.add(scroll, BorderLayout.CENTER);

        // Egy gomb a textbox mellé
        JButton editorButton = new JButton("Küld");
        editorPanel.add(editorButton, BorderLayout.EAST);
        editorButton.addActionListener(new SendButtonListener());
        editorButton.setFont(new Font("Dialog", Font.PLAIN, 11));
        editorButton.setContentAreaFilled(false);

        // Üzenetek kiírása
        control = new ArrayList<Message>();
        try {

            messenger = new Dropbox();
            config = messenger.getConfig();


            // Ha még nincs config file
            if (config.getMessagePath() == null || !config.getMessagePath().exists()) {
                // Message könyvtár kiválasztása
                File path;
                Object[] options = {"Kijelölés", "Kilépés"};
                int n = JOptionPane.showOptionDialog(null, "Nincsen megadva üzenetkönyvtár.", "DBM indulás", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
                
                if (n == 0) {
                    // File utvonal kiválasztás, és az érték visszaadása
                    final JFileChooser fc = new JFileChooser();
                    fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
                    int fcValue = fc.showOpenDialog(null);
                    if (fcValue == JFileChooser.APPROVE_OPTION) {
                        path = fc.getSelectedFile();
                        config.setMessagePath(path);
                    } else {
                        this.dispose();
                    }
                } else {
                    this.dispose();
                }
            }


            // Control fül létrehozása annak megfelelően van -e felhasználója
            control.add(new Message("Control", "Konfigurációs fájl sikeresen betöltve.", ""));
            control.add(new Message("Control", "Üzenetkönyvtár: " + messenger.getPath(), ""));
            if (config.getAutoLoginUsername().length() == 0) {

                control.add(new Message("Control", "Írd be a felhasználóneved!", ""));

            } else {

                this.login(config.getAutoLoginUsername());
            }
            tabber.updateTab("Control", control);


        } catch (IOException e) {
            somethingGoneWrong("Fájl hozzáférés sikertelen.");
        } catch (ConfigFileNotFoundException e) {
            somethingGoneWrong("Hiányzó konfigurációs fájl.");
        } catch (FileCorruptedException r) {
            somethingGoneWrong("Hibás konfigurációs fájl.");
        } finally {
            this.dispose();
        }

        // Üzenetkezelő algoritmus
        startUpdater();

    }

    // Frissítő indítás
    private void startUpdater() {
        if (config.getRefreshInterval() >= 1000) {
            updater = new Timer();
            updater.schedule(new Updater(), config.getRefreshInterval(), config.getRefreshInterval());
        }
    }
    
    // Frissítő
    private class Updater extends TimerTask {

        //private Map<String, Long> size = new HashMap<String, Long>();
        private long sumSize;

        public Updater() {
            this.sumSize = 0;
        }

        @Override
        // Run túlterhelés
        public void run() {
            try {
                update();
            } catch (IOException ex) {
                somethingGoneWrong("Fájl hozzáférés sikertelen.");
            } catch (FileCorruptedException ex) {
                somethingGoneWrong("Hibás felhasználói fájl.");
            } catch (NotLoggedInException ex) {
                somethingGoneWrong("Nem vagy belépve.");
            }

        }

        // Algoritmus a frissítésre
        private void update() throws IOException, FileCorruptedException, NotLoggedInException {

            System.out.println("check");
            if (config.getRefreshInterval() >= 1000) {
                long actSize = 0;

                // Méretek meghatározása
                for (String n : messenger.getAllUsers()) {
                    actSize += messenger.getUserFileSize(n);
                }

                // Ha megváltozott a file mérete frissítés
                if (actSize != sumSize) {
                    sumSize = actSize;
                    System.out.println(" now");
                    synchronized (messenger) {
                        messenger.loadAllUserMessages();
                    }
                    tabber.updateAllTabs();
                }
            }

        }
    }

    // Hibaüzenet küldő
    private void somethingGoneWrong(String error) {
        JOptionPane.showMessageDialog(this, error, "DBM Hiba", JOptionPane.ERROR_MESSAGE);
        control.add(new Message("Control", "Hiba: " + error, ""));
    }

    // Gomb eseményfigyelő
    private class SendButtonListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            submit();
        }
    }

    // Keyboard eseményfigyelő (ENTER)
    private class InputKeyListener implements KeyListener {

        @Override
        public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                submit();
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {
        }

        @Override
        public void keyTyped(KeyEvent e) {
        }
    }

    // Beléptetés
    private void login(String name) throws IOException, FileCorruptedException {
        
        // username bevétele és ennek megfelelően véltoztatások
        messenger.login(name);
        setTitle("DBM: " + name);
        control.add(new Message("Control", "Üdv, <b>" + name + "</b>!", ""));

        try {
            tabber.updateAllTabs();
        } catch (NotLoggedInException e) {
            // login error
        }
        tabber.updateTab("Control", control);
    }

    // Küldés
    private void submit() {
        try {

            String text = editor.getText().trim();
            editor.setText("");

            // Beírt üzenetek vizsgálata
            if (messenger.isLoggedIn()) {

                if (!text.equals("")) {
                    if (text.startsWith("/")) {

                        // help előhívása
                        if (text.equals("/help")) {
                            control.add(new Message(
                                    "Control",
                                    "<strong>Használható utasítások:</strong><br/><ul><li><strong>/t [téma] [üzenet]</strong><br/>Üzenet küldése megadott témába, ill. nem létező téma megadása esetén téma létrehozása. A témanév nem tartalmazhat szóközt.</li><li><strong>/f off|[int]</strong><br/>Automatikus frissítés kikapcsolása vagy a gyakoriság megadott értékre (>1000) való beállítása.</li></ul>",
                                    ""));
                            tabber.updateTab("Control", control);
                            tabber.setSelectedIndex(0);
                        }

                        // Új topic nyitása
                        if (text.startsWith("/t ")) {
                            String topic = text.substring(3, text.indexOf(' ', 3));
                            String message = text.substring(text.indexOf(' ', 3));
                            messenger.newMessage(topic, message);
                            tabber.newTab(topic);
                            tabber.updateTab(topic, messenger.getMessages(topic));
                        }
                        // Frissítés változtatás
                        if (text.startsWith("/f")) {
                            if (text.length() > 2) {
                                String option = text.substring(text.indexOf(' ') + 1);
                                // System.out.println("*" + option + "*");
                                if (option.equals("off")) {
                                    config.setRefreshInterval(0);
                                    updater.cancel();
                                    control.add(new Message("Control", "Automatikus frissítés kikapcsolva.", ""));
                                    tabber.updateTab("Control", control);
                                } else if (Integer.parseInt(option) > 1000) {
                                    config.setRefreshInterval(Integer.parseInt(option));
                                    startUpdater();
                                    control.add(new Message("Control", "Frissítési gyakoriság megváltozott, új érték: " + config.getRefreshInterval() + "ms", ""));
                                    tabber.updateTab("Control", control);
                                }
                            } else {
                                (new Updater()).run();
                            }
                        }
                    } else {
                        // Üzenet lett beírva a megfelelő fül frissül
                        String topic = tabber.getSelectedTopic();
                        if (!topic.equals("Control")) {
                            messenger.newMessage(topic, text);
                            tabber.updateTab(topic, messenger.getMessages(topic));
                        }
                    }
                } else {
                    // blank message
                }
            } else {

                // Felhasználó beléptetése
                String name = text;

                if (text.equals("")) {
                    somethingGoneWrong("A felhasználónévnek betűket kell tartalmaznia.");
                } else {

                    if (name.contains(" ")) {
                        name = name.substring(0, name.indexOf(' '));
                    }
                    if (messenger.userExists(name)) {
                        this.login(name);
                        int answer = JOptionPane.showConfirmDialog(this, "Szeretnél mindig " + name + " néven belépni a program indításakor?", "Automatikus bejelentkezés", JOptionPane.YES_NO_OPTION);
                        if (answer == 0) {
                            config.setAutoLoginUsername(name);
                            control.add(new Message("Control", name + ": automatikus bejelentkezés beállítva.", ""));
                            tabber.updateTab("Control", control);
                        }
                    } else {
                        int answer = JOptionPane.showConfirmDialog(this, name + ": felhasználó nem létezik. Szeretnéd létrehozni?", "Bejelentkezés", JOptionPane.YES_NO_OPTION);
                        if (answer == 0) {
                            messenger.newUser(name);
                            control.add(new Message("Control", name + ": felhasználói fájl létrehozva.", ""));
                            this.login(name);
                        }
                    }
                }
            }

        } catch (IOException e) {
            somethingGoneWrong("Fájl hozzáférés sikertelen.");
            e.printStackTrace();
        } catch (FileCorruptedException e) {
            somethingGoneWrong("Felhasználói fájl sérült.");
        } catch (NotLoggedInException e) {
            somethingGoneWrong("Nem vagy belépve.");
        } catch (UserAlreadyExistsException e) {
            somethingGoneWrong("A megadott felhasználónév már foglalt.");
        }
    }

    // Fülek osztálya
    private class MessageTabs extends JTabbedPane {

        private static final long serialVersionUID = 1L;
        private Map<String, JTextPane> tabs;

        // Konstruktor
        public MessageTabs() {
            super(JTabbedPane.TOP);
            this.setBorder(null);
            this.tabs = new HashMap<String, JTextPane>();
            this.newTab("Control");
        }

        // Topic fülek
        public String getSelectedTopic() {
            return ((Tab) this.getSelectedComponent()).title;
        }

        // Frissítés a füleken
        public void updateAllTabs() throws NotLoggedInException {
            for (String t : messenger.getTopics()) {
                tabber.updateTab(t, messenger.getMessages(t));
            }
        }

        // Üzeneteket ír a helyükre
        public void updateTab(String title, List<Message> messages) {

            if (!this.tabs.containsKey(title)) {
                this.newTab(title);
            }

            JTextPane output = this.tabs.get(title);
            String wall = "";
            for (Message m : messages) {
                wall += formatMessage(m);
            }
            output.setText(wall);
        }

        // Új fül alkotás
        private void newTab(String title) {
            if (!this.tabs.containsKey(title)) {
                
                Tab tabPanel = new Tab(title);
                JTextPane outputField = new JTextPane();
                JScrollPane slider = new JScrollPane(outputField);
                
                slider.setSize(new Dimension(100, 100));
                slider.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
                outputField.setEditable(false);
                // outputField.setAutoscrolls(true);
                outputField.setCaretPosition(outputField.getDocument().getLength());
                outputField.setContentType("text/html");
                tabPanel.add(slider);
                this.addTab(title, null, tabPanel, null);
                this.setEnabledAt(this.getTabCount() - 1, true);
                this.tabs.put(title, outputField);
            }
        }

        // Színek meghatározása
        private class StyleColorScheme {

            public final String color1;
            public final String color2;

            public StyleColorScheme(String c1, String c2) {
                this.color1 = c1;
                this.color2 = c2;
            }
        }
        private String styleLastUsername;
        private String styleLastTopic;
        private int styleActiveColor;

        
        // Kinézet meghatározás
        private String formatMessage(Message message) {
            Date date = new Date(message.getTimestamp());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy. MMM. dd k:mm");

            StyleColorScheme color[] = new StyleColorScheme[4];
            color[0] = new StyleColorScheme("#DBE9F3", "#9191b1"); // blue
            color[1] = new StyleColorScheme("#D5EAD6", "#80a080"); // green
            color[2] = new StyleColorScheme("#feeded", "#a08080"); // red
            color[3] = new StyleColorScheme("#F9F9C9", "#bbbb7f"); // yellow

            if (this.styleLastTopic == null) {
                this.styleLastTopic = message.getTopic();
            } else if (!message.getTopic().equals(this.styleLastTopic)) {
                this.styleLastUsername = null;
                this.styleLastTopic = message.getTopic();
                this.styleActiveColor = 0;
            }

            if (this.styleLastUsername != null) {

                if (!this.styleLastUsername.equals(message.getUsername())) {
                    this.styleActiveColor = (this.styleActiveColor == 0) ? 1 : 0;
                }
            } else {
                this.styleActiveColor = 0;
            }

            if (message.getTopic().equals("Control")) {
                this.styleActiveColor = 3;
            }

            this.styleLastUsername = message.getUsername();

            return "<div style=\"margin:0;padding:0 0 1px 0;background-color:"
                    + color[this.styleActiveColor].color2 + ";\"><div style=\"background:"
                    + color[this.styleActiveColor].color1
                    + ";margin:0;padding:3px;font-size:11;font-family:Arial;\">"
                    + message.getText() + "\t <span style=\"text-align:right;font-size:10;color:"
                    + color[this.styleActiveColor].color2 + ";\">-<b>" + message.getUsername()
                    + "</b> " + sdf.format(date) + "</span></div></div>";
        }

        // Fül osztály
        private class Tab extends JPanel {

            private static final long serialVersionUID = 1L;
            public final String title;

            public Tab(String title) {
                super();
                this.title = title;
                this.setLayout(new BorderLayout(0, 0));
            }
        }
    }
}
